package evaluador;

import controller.EstadisticaController;
import controller.MainController;
import java.util.ArrayList;

/*
 * AUTOR: RAFAEL ABERTO MORENO PARRA Evaluador de expresiones en Java.	01 de
 * Julio de 2010 http://darwin.50webs.com
 *
 * Licencia: LGPL GNU Lesser General Public License
 * (http://es.wikipedia.org/wiki/GNU_Lesser_General_Public_License)
 */
public class Evaluador {

    int filas;
    int columnas;
    public ArrayList<Integer> matrizR[][];
    public ArrayList<Double> matriz[][];

    public Evaluador(int filas, int columnas, ArrayList<Integer>[][] matrizR, ArrayList<Double>[][] matriz) {
        this.filas = filas;
        this.columnas = columnas;
        this.matrizR = matrizR;
        this.matriz = matriz;
        cFuncion = "sinsencostanabsasnacsatnlogceiexpsqrrcbpjpmip";
    }
//===================================== PARTE PRIVADA =========================================

    /*
     * Llegan bloques como 2+ 5- 6* 7- 3* 2^ 4* 5/ 6+ 4N y debe quedar así: 2+
     * 5- ACUM- 6* 7N ACUM+ 3/ ACUM * 5/ 6N 2^ 4N 4N
     */
    private String cFuncion;
    //Lista que tendrá la expresión analizada por acums
    private NodoSimple Analizado;
    private NodoSimple IniAnalizado;
    //Expresión simple como 3 + 5 - 2 + 1.5  - 7.6 + 2.471 - 6.901 - 0.0001
    private NodoSimple objNodo;
    //Mantiene la pista del último sumando
    private NodoSimple objPasea;
    //Mantiene la pista del último multiplicador
    private NodoSimple NodoMultip;
    //Mantiene la pista del último número de potencia
    private NodoSimple NodoPotencia;
    //Es TRUE si se activa una desviación de Multiplicación y División
    private int iMultipDivi;
    //Es TRUE si se activa una desviación de potencia
    private int iPotencia;

    private void vNuevoBloque(double fValor, char cOperador, char cVariable, NodoSimple objACUM) {
        /*
         * Llegan bloques como 2+ 5- 6* 7- 3* 2^ 4* 5/ 6+ 4N y debe quedar así:
         * 2+ 5- ACUM- 6* 7N ACUM- 3/ ACUM * 5/ 6N 2^ 4N 4N
         */

        //Creo el nuevo bloque a agregar a la expresión simple
        NodoSimple objNuevoBloque;
        if (objACUM == null) {
            if (cVariable == '@') {
                objNuevoBloque = new NodoSimple(fValor, cOperador);
            } else {
                objNuevoBloque = new NodoSimple(cVariable, cOperador);
            }
        } else {
            objNuevoBloque = new NodoSimple(objACUM, cOperador);
        }

        //Si el operador es una suma o resta agrega el nuevo nodo
        if ((cOperador == '+' || cOperador == '-' || cOperador == 'N') && iMultipDivi == 0) {
            objPasea.Abajo = objNuevoBloque;
            objPasea = objPasea.Abajo;
        } else //es una multiplicación o división o potencia
        {
            //Es la primera vez que sale * / ^
            if (iMultipDivi == 0) {
                //Se ha creado una desviación
                iMultipDivi = 1;

                //Crea un nodo ACUM multiplicador
                NodoMultip = new NodoSimple((double) 0, 'A');

                //La lista agrega a ACUM
                objPasea.Abajo = NodoMultip;

                //Se posa en ACUM
                objPasea = objPasea.Abajo;

                //Si es una potencia
                if (cOperador == '^') {
                    iPotencia = 1;

                    //Agrega por defecto un 1*
                    NodoSimple NodoMultiplica = new NodoSimple((double) 1, '*');

                    //Agrega el 1* al ACUM
                    NodoMultip.Derecha = NodoMultiplica;

                    //Crea un ACUMP (acumulador de potencia)
                    NodoPotencia = new NodoSimple((double) 0, 'B');

                    //Agrega el ACUMP a la multiplicación
                    NodoMultiplica.Derecha = NodoPotencia;

                    //Mueve NodoMultip hacia ACUMP
                    NodoMultip = NodoPotencia;

                    //ACUMP apunta al nuevo bloque
                    NodoPotencia.Potencia = objNuevoBloque;

                    //ACUMP se mueve a la última potencia
                    NodoPotencia = NodoPotencia.Potencia;
                } else {
                    //ACUM apunta a la derecha (para multiplicar y dividir)
                    NodoMultip.Derecha = objNuevoBloque;
                    NodoMultip = NodoMultip.Derecha;
                }
            } else //Ya había salido * / ^
            {
                //Si venia de una potencia por ejemplo:  5^4
                if (iPotencia == 1) {
                    //Agrega el potenciador, ejemplo: en 5^4 es decir ^4
                    NodoPotencia.Potencia = objNuevoBloque;
                    NodoPotencia = NodoPotencia.Potencia;

                    //Si lo que sigue no es una potencia entonces cierra la lista de potencias
                    if (cOperador != '^') {
                        iPotencia = 0;
                        NodoPotencia.cOperador = 'N';
                        if (cOperador == '*' || cOperador == '/') {
                            NodoMultip.cOperador = cOperador;
                        } else //Es una suma o una resta
                        {
                            NodoMultip.cOperador = '*';
                            objNuevoBloque = new NodoSimple((double) 1, 'N');
                            NodoMultip.Derecha = objNuevoBloque;
                            objPasea.cOperador = cOperador;
                            iMultipDivi = 0;
                        }
                    }
                } else {
                    if (cOperador == '^') {
                        iPotencia = 0;

                        //Crea un ACUMP (acumulador de potencia)
                        NodoPotencia = new NodoSimple((double) 0, 'B');

                        //Agrega el ACUMP a la multiplicación
                        NodoMultip.Derecha = NodoPotencia;

                        //Mueve NodoMultip hacia ACUMP
                        NodoMultip = NodoPotencia;

                        //ACUMP apunta al nuevo bloque
                        NodoPotencia.Potencia = objNuevoBloque;

                        //ACUMP se mueve a la última potencia
                        NodoPotencia = NodoPotencia.Potencia;
                    } else {
                        //Va hasta el último bloque de la derecha
                        NodoMultip.Derecha = objNuevoBloque;
                        NodoMultip = NodoMultip.Derecha;
                    }

                    //Si el nuevo bloque es numero+ o numero- entonces termina el enlace derecho
                    if (cOperador == '+' || cOperador == '-') {
                        iMultipDivi = 0;
                        objNuevoBloque.cOperador = 'N';
                        objPasea.cOperador = cOperador;
                    }
                }
            }
        }
    }

    //Evalúa rápidamente una serie de solo sumas y restas, desviandose en multiplicaciones y divisiones
    private double fEvaluaSumaResta() {
        double fTotal = objNodo.fNumero;
        char cOperador = objNodo.cOperador;
        while (cOperador != 'N') {
            objNodo = objNodo.Abajo; //Pasa al siguiente operador

            //Si detecta una desviación (multiplicación y división)
            if (objNodo.Derecha != null) {
                objNodo.fNumero = fEvaluaMultiplicaDivide(objNodo);
            }

            //Suma o resta
            if (cOperador == '+') {
                if (objNodo.objACUM != null) {
                    fTotal += objNodo.objACUM.fNumero;
                } else if (objNodo.cVariable == 0) {
                    fTotal += objNodo.fNumero;
                } else {
                    fTotal += fVariables[objNodo.cVariable];
                }
            } else if (objNodo.objACUM != null) {
                fTotal -= objNodo.objACUM.fNumero;
            } else if (objNodo.cVariable == 0) {
                fTotal -= objNodo.fNumero;
            } else {
                fTotal -= fVariables[objNodo.cVariable];
            }
            cOperador = objNodo.cOperador;
        }
        return fTotal;
    }

    //Evalúa rápidamente una serie de multiplicaciones y divisiones desviandose en potencias
    private double fEvaluaMultiplicaDivide(NodoSimple objMultiDivi) {
        //Se desplaza a la derecha para calcular multiplicaciones y divisiones
        objMultiDivi = objMultiDivi.Derecha;

        //Trae el primer operador
        double fTotal;
        if (objMultiDivi.objACUM != null) {
            fTotal = objMultiDivi.objACUM.fNumero;
        } else if (objMultiDivi.cVariable == 0) {
            fTotal = objMultiDivi.fNumero;
        } else {
            fTotal = fVariables[objMultiDivi.cVariable];
        }

        char cOperador = objMultiDivi.cOperador;
        while (cOperador != 'N') {
            objMultiDivi = objMultiDivi.Derecha;

            //Si detecta una desviación (potencias)
            if (objMultiDivi.Potencia != null) {
                objMultiDivi.fNumero = fEvaluaPotencia(objMultiDivi);
            }

            if (cOperador == '*') {
                if (objMultiDivi.objACUM != null) {
                    fTotal *= objMultiDivi.objACUM.fNumero;
                } else if (objMultiDivi.cVariable == 0) {
                    fTotal *= objMultiDivi.fNumero;
                } else {
                    fTotal *= fVariables[objMultiDivi.cVariable];
                }
            } else if (objMultiDivi.objACUM != null) {
                if (objMultiDivi.objACUM.fNumero != 0) {
                    fTotal /= objMultiDivi.objACUM.fNumero;
                } else {
                    ERRORMATEMATICO = DIVISIONENTRECERO;
                }
            } else if (objMultiDivi.cVariable == 0) {
                if (objMultiDivi.fNumero != 0) {
                    fTotal /= objMultiDivi.fNumero;
                } else {
                    ERRORMATEMATICO = DIVISIONENTRECERO;
                }
            } else if (fVariables[objMultiDivi.cVariable] != 0) {
                fTotal /= fVariables[objMultiDivi.cVariable];
            } else {
                ERRORMATEMATICO = DIVISIONENTRECERO;
            }
            cOperador = objMultiDivi.cOperador;
        }
        return fTotal;
    }

    //Evalúa rápidamente una serie de potencias
    private double fEvaluaPotencia(NodoSimple objPotencia) {
        //Se desplaza a la diagonal para calcular potencias
        objPotencia = objPotencia.Potencia;

        //Trae el primer operador
        double fTotal;
        if (objPotencia.objACUM != null) {
            fTotal = objPotencia.objACUM.fNumero;
        } else if (objPotencia.cVariable == 0) {
            fTotal = objPotencia.fNumero;
        } else {
            fTotal = fVariables[objPotencia.cVariable];
        }

        char cOperador = objPotencia.cOperador;
        while (cOperador != 'N') {
            objPotencia = objPotencia.Potencia;
            if (objPotencia.objACUM != null) {
                fTotal = (double) Math.pow(fTotal, objPotencia.objACUM.fNumero);
            } else if (objPotencia.cVariable == 0) {
                fTotal = (double) Math.pow(fTotal, objPotencia.fNumero);
            } else {
                fTotal = (double) Math.pow(fTotal, fVariables[objPotencia.cVariable]);
            }
            cOperador = objPotencia.cOperador;
        }
        return fTotal;
    }
//===================================== PARTE PUBLICA =========================================
    //Se activa si detecta un error matematico, caso contrario tiene el valor de cero
    public int ERRORMATEMATICO;
    public int NOERRORES = 0;
    public int DIVISIONENTRECERO = 1;
    public int ERRORARCOSENO = 2;
    public int ERRORARCOCOSENO = 3;
    //Las variables
    public double fVariables[] = new double[256];

    //Constructor
    public Evaluador() {
        //Las funciones serán siempre de tres letras
        cFuncion = "sinsencostanabsasnacsatnlogceiexpsqrrcbpjp";
    }

    /*
     * Evalua la sintaxis de la expresión. Retorna un entero que identifica los
     * tipos de error 0: Expresión correcta 1: Dos o más signos estén seguidos.
     * Ejemplo: 2++4, 5-*3 2: Un signo seguido de un paréntesis que cierra.
     * Ejemplo: 2-(4+)-7 3: Un parentesis que abre seguido de un signo. Ejemplo:
     * 2-(*3) 4: Que empiece con signo +, *, / . Ejemplo: /12-5*2 , *17-4 5: Que
     * termine con signo . Ejemplo: 12-67* 2/3- 6: Que los paréntesis estén
     * desbalanceados. Ejemplo: 3-(2*4)) 7: Que haya paréntesis vacío. Ejemplo:
     * 2-()*3 8: Así estén balanceados los paréntesis no corresponde el que abre
     * con el que cierra. Ejemplo: 2+3)-2*(4 9: Un paréntesis que cierra seguido
     * de un número. Ejemplo: (12-4)7-1 10: Un número seguido de un paréntesis
     * que abre. Ejemplo: 7-2(5-6) 11: Doble punto en un número de tipo real.
     * Ejemplo: 3-2..4+1 7-6.46.1+2 12: Función inexistente: Ejemplo: xyz(45)
     * 13: Función no seguida de paréntesis. Ejemplo: 2-sen5 14: Cadena está
     * vacía 15: Antes de la función no hay signo o parentesis que abre.
     * Ejemplo: 12cos(3) 16: Las variables solo son de una sola letra, no debe
     * haber dos letras seguidas. Ejemplo: 3-xy+2*ab 17: Una variable seguida de
     * un paréntesis que abre. Ejemplo: 7-x(5-6) 18: Un paréntesis que cierra
     * seguido de una variable. Ejemplo: (12-4)y-1 19: Una variable seguida de
     * un punto. Ejemplo: 4-z.1+3 20: Un punto seguido de una variable. Ejemplo:
     * 7-2.p+1 21: Un número antes o después de una variable. Ejemplo: 3x+1
     * x21+4 . Nota: Algebraicamente es aceptable 3x+1 pero entonces vuelve mas
     * complejo un evaluador porque debe saber que 3x+1 es en realidad 3*x+1 22:
     * Hayan caracteres extraños. 4+@-1
     *
     */
    public String MensajeSintaxis(String sExpresion) {
        String Respuesta = "";
        switch (iAnalizaSintaxis(sExpresion)) {
            case 0:
                Respuesta = "0: Expresión Correcta";
                break;
            case 1:
                Respuesta = "1: Dos o más signos estén seguidos.  Ejemplo: 2++4, 5-*3";
                break;
            case 2:
                Respuesta = "2: Un signo seguido de un paréntesis que cierra.  Ejemplo: 2-(4+)-7";
                break;
            case 3:
                Respuesta = "3: Un paréntesis que abre seguido de un signo. Ejemplo: 2-(*3)";
                break;
            case 4:
                Respuesta = "4: Que empiece con signo +, *, / . Ejemplo: /12-5*2 ,  *17-4";
                break;
            case 5:
                Respuesta = "5: Que termine con signo . Ejemplo:  12-67*  2/3-";
                break;
            case 6:
                Respuesta = "6: Que los paréntesis estén desbalanceados. Ejemplo:  3-(2*4))";
                break;
            case 7:
                Respuesta = "7: Que haya paréntesis vacío. Ejemplo:  2-()*3";
                break;
            case 8:
                Respuesta = "8: Así estén balanceados los paréntesis no corresponde el que abre con el que cierra. Ejemplo: 2+3)-2*(4";
                break;
            case 9:
                Respuesta = "9: Un paréntesis que cierra seguido de un número. Ejemplo: (12-4)7-1";
                break;
            case 10:
                Respuesta = "10: Un número seguido de un paréntesis que abre. Ejemplo: 7-2(5-6)";
                break;
            case 11:
                Respuesta = "11: Doble punto en un número de tipo real. Ejemplo: 3-2..4+1   7-6.46.1+2";
                break;
            case 12:
                Respuesta = "12: Función inexistente:  Ejemplo: xyz(45)";
                break;
            case 13:
                Respuesta = "13: Función no seguida de paréntesis. Ejemplo: 2-sen5";
                break;
            case 14:
                Respuesta = "14: Cadena está vacía";
                break;
            case 15:
                Respuesta = "15: Antes de la función no hay signo o parentesis que abre. Ejemplo: 12cos(3)";
                break;
            case 16:
                Respuesta = "16: Las variables solo son de una sola letra, no debe haber dos letras seguidas. Ejemplo: 3-xy+2*ab";
                break;
            case 17:
                Respuesta = "17: Una variable seguida de un paréntesis que abre. Ejemplo: 7-x(5-6)";
                break;
            case 18:
                Respuesta = "18: Un paréntesis que cierra seguido de una variable. Ejemplo: (12-4)y-1";
                break;
            case 19:
                Respuesta = "19: Una variable seguida de un punto. Ejemplo: 4-z.1+3";
                break;
            case 20:
                Respuesta = "20: Un punto seguido de una variable. Ejemplo: 7-2.p+1";
                break;
            case 21:
                Respuesta = "21: Un número antes o después de una variable. Ejemplo: 3x+1  x21+4  . Nota: Algebraicamente es aceptable 3x+1 pero entonces vuelve mas complejo un evaluador porque debe saber que 3x+1 es en realidad 3*x+1";
                break;
            case 22:
                Respuesta = "22: Hayan caracteres extraños.  4+@-1";
                break;
        }
        return Respuesta;
    }

    public int iAnalizaSintaxis(String sExpresion) {
        //Saca una copia de la expresión del usuario en otra variable y así poder trabajar esa variable
        //Retira los espacios y vuelve a minúsculas toda la expresión
        String sNueva = "";
        for (int iLetra = 0; iLetra < sExpresion.length(); iLetra++) {
            if (sExpresion.charAt(iLetra) != ' ') {
                sNueva += sExpresion.charAt(iLetra);
            }
        }
        sNueva = sNueva.toLowerCase();

        //14: Cadena está vacía
        if (sNueva.length() == 0) {
            return 14;
        }

        //Convierte la cadena a un arreglo unidimensional de caracteres
        int TamanoExpresion = sNueva.length();
        int iCont;
        char Arreglo[] = new char[TamanoExpresion];
        for (iCont = 0; iCont < TamanoExpresion; iCont++) {
            Arreglo[iCont] = sNueva.charAt(iCont);
        }

        // *4: Que empiece con signo +, *, / . Ejemplo: /12-5*2 ,  *17-4
        if (Arreglo[0] == '^' || Arreglo[0] == '*' || Arreglo[0] == '+' || Arreglo[0] == '/') {
            return 4;
        }

        //15: Antes de la función no hay signo o parentesis que abre. Ejemplo: 12cos(3)
        for (iCont = 1; iCont < TamanoExpresion - 2; iCont++) {
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    if (Arreglo[iCont + 2] >= 'a' && Arreglo[iCont + 2] <= 'z') {
                        if (Arreglo[iCont - 1] != '(' && Arreglo[iCont - 1] != '+' && Arreglo[iCont - 1] != '-' && Arreglo[iCont - 1] != '*' && Arreglo[iCont - 1] != '/' && Arreglo[iCont - 1] != '^') {
                            return 15;
                        }
                    }
                }
            }
        }

        //13: Función no seguida de paréntesis que abre. Ejemplo: 2-sen5
        for (iCont = 0; iCont < TamanoExpresion - 3; iCont++) {
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    if (Arreglo[iCont + 2] >= 'a' && Arreglo[iCont + 2] <= 'z') {
                        if (Arreglo[iCont + 3] != '(') {
                            return 13;
                        }
                    }
                }
            }
        }

        //12: Función inexistente:  Ejemplo: xyz(45)
        int TamanoFuncion = cFuncion.length();
        for (iCont = 0; iCont < TamanoExpresion - 2; iCont++) {
            boolean bNoExiste = true;
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    if (Arreglo[iCont + 2] >= 'a' && Arreglo[iCont + 2] <= 'z') {
                        for (int iPosible = 0; iPosible < TamanoFuncion; iPosible += 3) {
                            if (cFuncion.charAt(iPosible) == Arreglo[iCont] && cFuncion.charAt(iPosible + 1) == Arreglo[iCont + 1] && cFuncion.charAt(iPosible + 2) == Arreglo[iCont + 2]) {
                                bNoExiste = false;
                            }
                        }

                        if (bNoExiste) {
                            return 12;
                        }
                    }
                }
            }
        }

        for (iCont = 0; iCont < TamanoExpresion - 1; iCont++) {
            //19: Una variable seguida de un punto. Ejemplo: 4-z.1+3
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] == '.') {
                    return 19;
                }
            }

            //20: Un punto seguido de una variable. Ejemplo: 7-2.p+1
            if (Arreglo[iCont] == '.') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    return 20;
                }
            }

            //18: Un paréntesis que cierra seguido de una variable. Ejemplo: (12-4)y-1
            if (Arreglo[iCont] == ')') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    return 18;
                }
            }

            //1: Dos o más signos estén seguidos.  Ejemplo: 2++4, 5-*3
            if (Arreglo[iCont] == '+' || Arreglo[iCont] == '-' || Arreglo[iCont] == '*' || Arreglo[iCont] == '/' || Arreglo[iCont] == '^') {
                if (Arreglo[iCont + 1] == '+' || Arreglo[iCont + 1] == '-' || Arreglo[iCont + 1] == '*' || Arreglo[iCont + 1] == '/' || Arreglo[iCont + 1] == '^') {
                    return 1;
                }
            }

            //2: Un signo seguido de un paréntesis que cierra.  Ejemplo: 2-(4+)-7
            if (Arreglo[iCont] == '+' || Arreglo[iCont] == '-' || Arreglo[iCont] == '*' || Arreglo[iCont] == '/' || Arreglo[iCont] == '^') {
                if (Arreglo[iCont + 1] == ')') {
                    return 2;
                }
            }

            //3: Un parentesis que abre seguido de un signo. Ejemplo: 2-(*3)
            if (Arreglo[iCont] == '(') {
                if (Arreglo[iCont + 1] == '+' || Arreglo[iCont + 1] == '*' || Arreglo[iCont + 1] == '/' || Arreglo[iCont + 1] == '^') {
                    return 3;
                }
            }

            //7: Un parentesis que abre seguido de un signo. Ejemplo: 2-(*3)
            if (Arreglo[iCont] == '(' && Arreglo[iCont + 1] == ')') {
                return 7;
            }

            //9: Un paréntesis que cierra seguido de un número. Ejemplo: (12-4)7-1
            if (Arreglo[iCont] == ')' && Arreglo[iCont + 1] >= '0' && Arreglo[iCont + 1] <= '9') {
                return 9;
            }

            //10: Un número seguido de un paréntesis que abre. Ejemplo: 7-2(5-6)
            if (Arreglo[iCont] >= '0' && Arreglo[iCont] <= '9' && Arreglo[iCont + 1] == '(') {
                return 10;
            }
        }

        //6: Que los paréntesis estén desbalanceados. Ejemplo:  3-(2*4))
        int iParentesis = 0;
        for (iCont = 0; iCont < TamanoExpresion; iCont++) {
            if (Arreglo[iCont] == '(') {
                iParentesis++;
            }
            if (Arreglo[iCont] == ')') {
                iParentesis--;
            }
        }
        if (iParentesis != 0) {
            return 6;
        }

        //8: Así estén balanceados los paréntesis no corresponde el que abre con el que cierra. Ejemplo: 2+3)-2*(4
        //11: Doble punto en un número de tipo real. Ejemplo: 3-2..4+1   7-6.46.1+2
        int iPunto = 0;
        for (iCont = 0; iCont < TamanoExpresion; iCont++) {
            if (Arreglo[iCont] == '(') {
                iParentesis++;
            }
            if (Arreglo[iCont] == ')') {
                iParentesis--;
            }
            if (iParentesis < 0) {
                return 8;
            }

            if (Arreglo[iCont] == '+' || Arreglo[iCont] == '-' || Arreglo[iCont] == '*' || Arreglo[iCont] == '/' || Arreglo[iCont] == '^') {
                iPunto = 0;
            }

            if (Arreglo[iCont] == '.') {
                iPunto++;
            }
            if (iPunto > 1) {
                return 11;
            }
        }

        //5: Que termine con signo . Ejemplo:  12-67*  2/3-
        if (Arreglo[TamanoExpresion - 1] == '^' || Arreglo[TamanoExpresion - 1] == '-' || Arreglo[TamanoExpresion - 1] == '*' || Arreglo[TamanoExpresion - 1] == '+' || Arreglo[TamanoExpresion - 1] == '/') {
            return 5;
        }

        //Chequea las funciones, va de atrás hacia adelante buscando un ( y luego extrae las tres letras
        char cLetraA, cLetraB, cLetraC;
        for (iCont = TamanoExpresion - 1; iCont >= 3; iCont--) {
            if (Arreglo[iCont] == '(') {
                cLetraA = Arreglo[iCont - 3];
                cLetraB = Arreglo[iCont - 2];
                cLetraC = Arreglo[iCont - 1];
                System.out.println(cFuncion.length());
                //Busca esas tres letras en cFuncion
                for (int iLetra = 0; iLetra <= cFuncion.length() - 3; iLetra += 3) {
                    if (cLetraA == cFuncion.charAt(iLetra) && cLetraB == cFuncion.charAt(iLetra + 1) && cLetraC == cFuncion.charAt(iLetra + 2)) {
                        Arreglo[iCont - 3] = '0';
                        Arreglo[iCont - 2] = '0';
                        Arreglo[iCont - 1] = '+';
                    }
                }
            }
        }

        //Chequea si quedan dos o mas variables seguidas
        for (iCont = 0; iCont < TamanoExpresion - 1; iCont++) {
            //16: Las variables solo son de una sola letra, no debe haber dos letras seguidas. Ejemplo: 3-xy+2*ab
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    return 16;
                }
            }

            //17: Una variable seguida de un paréntesis que abre. Ejemplo: 7-x(5-6)
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] == '(') {
                    return 17;
                }
            }

            //21: Un número antes o después de una variable. Ejemplo: 3x+1  x21+4  . Nota: Algebraicamente es aceptable 3x+1 pero entonces vuelve mas complejo un evaluador porque debe saber que 3x+1 es en realidad 3*x+1
            if (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z') {
                if (Arreglo[iCont + 1] >= '0' && Arreglo[iCont + 1] <= '9') {
                    return 21;
                }
            }

            if (Arreglo[iCont] >= '0' && Arreglo[iCont] <= '9') {
                if (Arreglo[iCont + 1] >= 'a' && Arreglo[iCont + 1] <= 'z') {
                    return 21;
                }
            }
        }

        //Chequea si hay caracteres extraños
        for (iCont = 0; iCont < TamanoExpresion; iCont++) {
            if ((Arreglo[iCont] >= '0' && Arreglo[iCont] <= '9')
                    || (Arreglo[iCont] >= 'a' && Arreglo[iCont] <= 'z')
                    || Arreglo[iCont] == '+' || Arreglo[iCont] == '-'
                    || Arreglo[iCont] == '*' || Arreglo[iCont] == '/'
                    || Arreglo[iCont] == '^'
                    || Arreglo[iCont] == '(' || Arreglo[iCont] == ')') {
                Arreglo[iCont] = '.';
            }
        }

        //22: Hayan caracteres extraños.  4+@-1
        for (iCont = 0; iCont < TamanoExpresion; iCont++) {
            if (Arreglo[iCont] != '.') {
                return 22;
            }
        }

        //No hay errores sintácticos
        return 0;
    }

    //Recibe la expresión matemática y la analiza dejándola construida en un grafo.
    public void vAnaliza(String sExpresion) {
        //Conversión de string a double
        double fValor = 0L;
        double iDecimal = 0L;
        double iFraccion = 0L;
        double dDivide = 1L;
        boolean bPunto = false;

        //Manejo de funciones
        int iFuncion;

        //Manejo de subexpresiones
        char cVariable = '@';
        int iACUM;
        int iACUMULADO = 1;
        NodoSimple objACUMULADOR = null;

        //Para añadir nodos a la lista doblemente enlazada. Empieza con paréntesis que abre.
        NodoDoble objListaDoble = new NodoDoble('(');

        //Queda la expresión en una lista doblemente enlazada donde cada Nodo tiene un caracter
        String sNueva = sExpresion.toLowerCase();
        for (int iLetra = 0; iLetra < sNueva.length(); iLetra++) {
            if (sNueva.charAt(iLetra) != ' ') //Quita automáticamente los espacios
            {
                objListaDoble = new NodoDoble(sNueva.charAt(iLetra), objListaDoble);
            }
        }

        objListaDoble = new NodoDoble(')', objListaDoble); //Termina la expresión con paréntesis que cierra

        //==========================================
        //Inicializa la lista de expresión analizada
        //==========================================
        Analizado = null;
        IniAnalizado = null;

        //Deshace en subexpresiones ACUM
        NodoDoble objFin, objIni, objTemp;
        while (objListaDoble != null) {
            //Extrae la subcadena entre paréntesis, si encuentra el paréntesis que abre
            if (objListaDoble.cLetra == '(') {
                //Coloca una marca donde esta el paréntesis que abre
                objIni = objListaDoble;

                //Busca el paréntesis que cierra, de esa manera extrae lo interior
                while (objListaDoble.cLetra != ')') {
                    objListaDoble = objListaDoble.FlechaD;
                }

                //Pone una marca donde está el paréntesis que cierra
                objFin = objListaDoble;

                // ============================================================================
                // Análisis de una expresión simple
                // ============================================================================

                //Adiciona un nodo a la lista con expresión analizada
                if (Analizado == null) {
                    Analizado = new NodoSimple();
                    IniAnalizado = Analizado;
                } else {
                    Analizado = new NodoSimple(Analizado);
                }

                //Inicializa para evaluar la expresión simple
                objNodo = new NodoSimple((double) 0, '+');
                objPasea = objNodo;
                iMultipDivi = 0; //Desviación multiplicación falsa
                iPotencia = 0; //Desviación potencia falsa

                //Si tiene un - al inicio entonces lo convierte a 0-
                boolean bNegativoInicio = false;
                if (objIni.FlechaD.cLetra == '-') {
                    bNegativoInicio = true; //Tiene en cuenta que hay un - al inicio
                }
                //Envía a analizar la subexpresión entre paréntesis
                NodoDoble objExtrae = objIni;
                while (objExtrae.FlechaD != objFin) {
                    //Empieza a traer caracter por caracter desde el paréntesis (
                    objExtrae = objExtrae.FlechaD;

                    //Si es un ACUM entonces crea la referencia a ese bloque
                    if (objExtrae.iACUM >= 0) {
                        //Busca el ACUM a referir
                        iACUM = 1;
                        objACUMULADOR = IniAnalizado;
                        while (iACUM < objExtrae.iACUM) {
                            objACUMULADOR = objACUMULADOR.Abajo;
                            iACUM++;
                        }
                    } //Si son números entonces los va acumulando en un "string"
                    else if ((objExtrae.cLetra >= '0' && objExtrae.cLetra <= '9') || objExtrae.cLetra == '.') {
                        if (objExtrae.cLetra == '.') {
                            bPunto = true;
                        } else if (bPunto == false) {
                            iDecimal = iDecimal * 10 + objExtrae.cLetra - 48;
                        } else {
                            iFraccion = iFraccion * 10 + objExtrae.cLetra - 48;
                            dDivide *= 10L;
                        }

                        cVariable = '@'; //No es variable
                        objACUMULADOR = null; //No es acumulador
                    } else if (objExtrae.cLetra >= 'a' && objExtrae.cLetra <= 'z') {
                        objACUMULADOR = null; //No es acumulador
                        cVariable = objExtrae.cLetra;
                    } else //Es +, -, *, /, ^ entonces crea un nuevo bloque de "numero operador" o "variable operador" o "acumulado operador"
                    {
                        fValor = iDecimal + iFraccion / dDivide;
                        iDecimal = iFraccion = 0L;
                        dDivide = 1L;
                        bPunto = false;
                        if (bNegativoInicio) {
                            vNuevoBloque(0, '-', '0', null);
                            bNegativoInicio = false;
                        } else {
                            vNuevoBloque((double) fValor, objExtrae.cLetra, cVariable, objACUMULADOR);
                        }
                        objACUMULADOR = null;
                    }
                }

                //El último operando, la expresión debe terminar en "+0N"
                fValor = iDecimal + iFraccion / dDivide;
                iDecimal = iFraccion = 0L;
                dDivide = 1L;
                bPunto = false;
                vNuevoBloque((double) fValor, '+', cVariable, objACUMULADOR);
                vNuevoBloque(0, 'N', '0', null);

                //Coloca en la lista de expresión analizada
                Analizado.Derecha = objNodo;

                //Es un ACUM y lo marca con un código ascendente
                objIni.iACUM = iACUMULADO++;

                //Borra la subexpresion de la lista doblemente enlazada (incluye liberar la memoria)
                objIni.FlechaD = objFin.FlechaD;
                if (objIni.FlechaI == null) {
                    break;
                }

                //Chequea si las tres letras anteriores corresponden a una función conocida
                if (objIni.FlechaI.cLetra >= 'a' && objIni.FlechaI.cLetra <= 'z') {
                    //Retrocede tres letras
                    objIni = objIni.FlechaI.FlechaI.FlechaI;

                    iFuncion = 1;
                    for (int Letra = 0; Letra < cFuncion.length(); Letra += 3) {
                        if (objIni.cLetra == cFuncion.charAt(Letra)
                                && objIni.FlechaD.cLetra == cFuncion.charAt(Letra + 1)
                                && objIni.FlechaD.FlechaD.cLetra == cFuncion.charAt(Letra + 2)) {
                            objNodo = new NodoSimple();
                            objNodo.iFuncion = iFuncion;
                            Analizado = new NodoSimple(Analizado);
                            Analizado.Derecha = objNodo;
                            break;
                        }
                        iFuncion++;
                    }

                    //Borra los nodos sobrantes
                    objTemp = objIni.FlechaD.FlechaD.FlechaD.FlechaD;
                    objIni.FlechaD = objTemp;
                    objIni.iACUM = iACUMULADO++;
                }

                //Restaura para evaluar siguiente paréntesis
                objListaDoble = objIni.FlechaI;
            } else {
                objListaDoble = objListaDoble.FlechaI;
            }
        }

    }

    //Evalua la expresión ya analizada
    public double fEvaluar() {
        ERRORMATEMATICO = NOERRORES;
        double fValor = 0;
        NodoSimple objNavegar;
        objNavegar = IniAnalizado;
        while (true) {
            if (objNavegar.Derecha != null) {
                objNodo = objNavegar.Derecha;
                if (objNodo.iFuncion == 0) {
                    fValor = fEvaluaSumaResta();
                    objNavegar.fNumero = fValor;
                    if (ERRORMATEMATICO != 0) {
                        return 0;
                    }
                } else //Evalua la función
                {
                    switch (objNodo.iFuncion) {
                        case 1:
                        case 2: //Seno
                            objNavegar.fNumero = (double) Math.sin(fValor);
                            break;
                        case 3: //Coseno
                            objNavegar.fNumero = (double) Math.cos(fValor);
                            break;
                        case 4: //Tangente
                            objNavegar.fNumero = (double) Math.tan(fValor);
                            break;
                        case 5: //valor absoluto
                            if (fValor < 0) {
                                objNavegar.fNumero = (double) -fValor;
                            } else {
                                objNavegar.fNumero = (double) fValor;
                            }
                            break;
                        case 6: //arcoseno
                            if (fValor >= -1 && fValor <= 1) {
                                objNavegar.fNumero = (double) Math.asin(fValor);
                            } else {
                                objNavegar.fNumero = 0;
                                ERRORMATEMATICO = ERRORARCOSENO;
                                return 0;
                            }
                            break;
                        case 7: //arcocoseno
                            if (fValor >= -1 && fValor <= 1) {
                                objNavegar.fNumero = (double) Math.acos(fValor);
                            } else {
                                objNavegar.fNumero = 0;
                                ERRORMATEMATICO = ERRORARCOCOSENO;
                                return 0;
                            }
                            break;
                        case 8: //arcotangente
                            objNavegar.fNumero = (double) Math.atan(fValor);
                            break;
                        case 9: //Logaritmo
                            objNavegar.fNumero = (double) Math.log(fValor);
                            break;
                        case 10: //Valor techo
                            objNavegar.fNumero = (double) Math.ceil(fValor);
                            break;
                        case 11: //Exponencial
                            objNavegar.fNumero = (double) Math.exp(fValor);
                            break;
                        case 12: //Raiz Cuadrada
                            objNavegar.fNumero = (double) Math.sqrt(fValor);
                            break;
                        case 13: //Raiz Cubica 
                            objNavegar.fNumero = (double) Math.pow(fValor, (double) 1 / 3);
                            break;
                        case 14:
                            objNavegar.fNumero = ((double[]) EstadisticaController.calcularRpuntoJpunto(matrizR))[(int)fValor];
                            break;
                        case 15:
                            objNavegar.fNumero = (double)EstadisticaController.calcularMIPunto(matriz,(int)fValor);
                            
                            break;
                    }
                }
            }

            //Condición de salida
            if (objNavegar.Abajo != null) {
                objNavegar = objNavegar.Abajo;
            } else {
                break;
            }
        }
        return objNavegar.fNumero;
    }

    private double sumatoriaI(double fValor) {
        for (int i = 0; i <filas; i++) {
            //fValor
        }
        return 0.0;
    }
}
